/*
 * Logger.java
 *
 * Copyright (C) 2005-2008 Tommi Laukkanen
 * http://www.substanceofcode.com
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */
package de.hauck.rtmidlet.utils;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;


import javax.microedition.io.Connector;
import javax.microedition.io.file.FileConnection;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Form;

import de.hauck.rtmidlet.model.Configuration;

/**
 * A Very rough Logger class.
 * 
 * @author Barry Redmond
 */
public class MyLogger {

	private Configuration c;
	/**
	 * Max 2000 characters logged at one time
	 */
	private static final int DEFAULT_MAX_SIZE = 2000;

	/**
	 * Severe errors that cause premature termination. Expect these to be
	 * immediately visible on a status console.
	 */
	public static final int FATAL = 5;
	/**
	 * Other runtime errors or unexpected conditions. Expect these to be
	 * immediately visible on a status console.
	 */
	public static final int ERROR = 4;
	/**
	 * Use of deprecated APIs, poor use of API, 'almost' errors, other runtime
	 * situations that are undesirable or unexpected, but not necessarily
	 * "wrong". Expect these to be immediately visible on a status console.
	 */
	public static final int WARN = 3;
	/**
	 * Interesting runtime events (startup/shutdown). Expect these to be
	 * immediately visible on a console, so be conservative and keep to a
	 * minimum.
	 */
	public static final int INFO = 2;
	/**
	 * Detailed information on flow of through the system. Expect these to be
	 * written to logs only.
	 */
	public static final int DEBUG = 1;

	private static final String[] LEVEL_NAMES = { "ALL", "DEBUG", "INFO",
			"WARN", "ERROR", "FATAL", "OFF" };
	public static final int OFF = 6;
	public static final int ALL = 0;

	private static MyLogger logger;

	// private Displayable previous;

	private StringBuffer buffer;
	private int maxSize;

	private long lastLoggedAt = 0; // Timestamp of the lastlogged message

	private int loggingLevel;

	private static final String LogFileName = "RTMidlet.txt";

	private FileConnection logConnection;
	private WorkerThread workerThread;

	// Assume first that file writing is possible
	// private boolean fileWritingPossible = true;

	public static void init() { // RecorderSettings settings) {
		if (logger == null) {
			logger = new MyLogger(); // settings);
		}
	}

	public static MyLogger getLogger() throws NullPointerException {
		if (logger == null) {
			throw new NullPointerException("logger_get_logger_error");
		}
		return logger;
	}

	/**
	 * Utility method to put a debug log message
	 * 
	 * @param message
	 */
	public static void debug(String message) {
		logger.log(message, DEBUG);
	}

	public static void info(String message) {
		logger.log(message, INFO);
	}

	public static void warn(String message) {
		logger.log(message, WARN);
	}

	public static void error(String message) {
		logger.log(message, ERROR);
	}

	public static void fatal(String message) {
		logger.log(message, FATAL);
		System.err.println("ERROR: " + message);
	}

	private MyLogger() {// RecorderSettings settings) {
		// super("Logger");
		this.buffer = new StringBuffer();
		this.maxSize = DEFAULT_MAX_SIZE;
		// this.settings = settings;
		// this.setLoggingLevel(0); //.getLoggingLevel());
		// refreshWriteLogCommand();
		this.refresh();
	}

	private String lastMessage;
	private int lastMessageLevel = -1;
	private int numOfLastMessage;

	private void log(String message, int level) {

		System.out.println(level + ") " + message);
		if (level < DEBUG || level > FATAL) {
			throw new IllegalArgumentException("Loglevel " + level + " unknown");
		}
		if (level < loggingLevel) {
			return;
		}
		synchronized (buffer) {

			if (level == lastMessageLevel && message.equals(this.lastMessage)) {
				numOfLastMessage++;
				if (numOfLastMessage == 2) {
					buffer.append("(x" + numOfLastMessage + ")");
				} else {
					int numToDelete = 2;// at least one digit, plus ')' char.
					int temp = numOfLastMessage - 1;
					while ((temp = temp / 10) > 0) {
						numToDelete++;
					}
					buffer.delete(buffer.length() - numToDelete, buffer
							.length());
					buffer.append(numOfLastMessage + ")");
				}
			} else {
				lastMessage = message.toString();
				lastMessageLevel = level;
				numOfLastMessage = 1;

				int messageLength = message.length();
				if (messageLength + buffer.length() > maxSize) {
					if (messageLength < maxSize) {
						buffer.delete(0, messageLength);
					} else {
						buffer.delete(0, buffer.length());
					}
				}

				buffer.append(message).append(' ').append('\n');

				lastLoggedAt = System.currentTimeMillis();
				if (c.logOn) { // settings.getWriteLog()) {
					if (null==workerThread && Configuration.exportPath!=null) {
						workerThread=new WorkerThread();
						workerThread.start();
					}
					writeToFileSystem(message);
					
				}
			}
		}
	}

	// public void log(String message, byte level){
	// this.log(new StringBuffer(message), level);
	// }

	public void refresh() {
		// .deleteAll();
		// if (buffer.length() == 0) {
		// this.append("logger_nothing_logged");
		// } else {
		// this.append(buffer.toString());
		// }
	}

	public void setLoggingLevel(int level) {
		if (level < ALL || level > OFF) {
			throw new IllegalArgumentException("unknown log level");
		}
		// settings.setLoggingLevel(level);
		this.loggingLevel = level;
		// if (loggingLevel == OFF || loggingLevel == ALL) {
		// this.setTitle(LocaleManager.getMessage("logger_lot_title_logging")
		// + " " + LEVEL_NAMES[loggingLevel]);
		// } else {
		// this.setTitle(LocaleManager.getMessage("logger_lot_title_logging_at")
		// + " " + LEVEL_NAMES[loggingLevel]);

	}

	public int getLoggingLevel() {
		return this.loggingLevel;
	}

	/**
	 * Returns the last logged message
	 * 
	 * @return The last logged message
	 */
	public String getLastMessage() {
		return lastMessage;
	}

	/**
	 * Returns the date the last logged message was recorded at
	 * 
	 * @return Date
	 */
	public long getTimeOfLastMessage() {
		return lastLoggedAt;
	}

	/**
	 * Writes out the Log to the filesystem.
	 * 
	 * @return
	 */
	public void writeToFileSystem(String message) {
		// If file writing isn't possible give up immediately
		if (!Configuration.fileWritingPossible
				|| Configuration.exportPath == null) {
			return;
		}

		// MyLoggerFSWriterThread mylog = new MyLoggerFSWriterThread(message);
		workerThread.go(message);

//		try {
//
//			// String exportFolder = "Speicherkarte/";
//			// //Controller.getController().getSettings()
//			// .getExportFolder();
//			// fullPath = "file:///" + exportFolder + LogFileName;
//			String fullPath = "file:///" + Configuration.exportPath
//					+ LogFileName;
//			DataOutputStream streamOut = null;
//
//			try {
//				// ------------------------------------------------------------------
//				// Create a FileConnection and if this is a new stream create
//				// the
//				// file
//				// ------------------------------------------------------------------
//
//				// Logger.debug("FILE: path is " + fullPath);
//				if (logConnection == null) {
//					try {
//						logConnection = (FileConnection) Connector
//								.open(fullPath);
//						// Create file
//						if (logConnection != null && !logConnection.exists()) {
//							logConnection.create();
//						} else {
//							// File already exists: zero the contents so we get
//							// a new log each time
//							// logConnection.delete();
//							logConnection.create();
//						}
//					} catch (IOException e) {
//						Configuration.fileWritingPossible = false;
//						MyLogger.debug("WriteLog failed to create connection:"
//								+ fullPath + ":" + e.getMessage());
//						logConnection = null;
//					}
//				}
//
//				if (logConnection != null && streamOut == null) { // XXX:
//																	// streamOut
//																	// is always
//																	// null
//																	// here?
//					// open the stream at the end so we can append to the file
//					System.out.println("Filesize:" + logConnection.fileSize());
//					OutputStream x = logConnection
//							.openOutputStream(logConnection.fileSize());
//					streamOut = new DataOutputStream(x);
//				}
//
//				if (streamOut != null) {
//					streamOut.write(((String) message + "\n").getBytes());
//					streamOut.flush();
//					streamOut.close();
//					streamOut = null;
//				} else {
//					Configuration.fileWritingPossible = false;
//					MyLogger.debug("Logger: output stream is null");
//				}
//			} catch (IOException e) {
//				Configuration.fileWritingPossible = false;
//				MyLogger.debug("Logger: error:" + e.getMessage());
//				e.printStackTrace();
//			}
//		} catch (Exception e) {
//		}
	}
}